//============================================================================
// Name        : TomogramClassificator.cpp
// Author      : Jaime Pavlich-Mariscal
// Version     :
// Copyright   : Your copyright notice
// Description :
//============================================================================

#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <map>
#include <string>
#include <iostream>
#include <fstream>
#include <cv.h>
#include <highgui.h>

using namespace std;
using namespace cv;

double rand(double min, double max) {
	double r = ((double) rand() / (double) RAND_MAX);
	return r * (max - min) + min;
}

vector<string> listFiles(const char* dir, const char* substr) {
	vector<string> files;
	DIR *dp;
	struct dirent *dirp;
	if ((dp = opendir(dir)) == NULL) {
		cout << "Error(" << errno << ") opening " << dir << endl;
	}
	string fname;
	while ((dirp = readdir(dp)) != NULL) {
		//		cout << dirp->d_name;
		fname = dirp->d_name;

		if (fname.find(substr) != fname.npos) {
			files.push_back(fname);
			//			cout << " * ";
		}
		//		cout << endl;
	}
	closedir(dp);
	sort(files.begin(), files.end());
	return files;
}



bool map_comparer(map<int, double>::value_type &it1,
		map<int, double>::value_type &it2) {
	return it1.second < it2.second;
}

/*!
 * Calculates Sobel gradients on tomograms
 */
void testSobel() {
	vector<string> files = listFiles(".", "png");
	typedef map<int, double> V;
	map<string, V> sds;
	map<string, V> ms;
	map<string, double> maxSd;
	map<string, double> minSd;
	map<string, double> maxMean;
	map<string, double> minMean;

	ofstream ofs("out.csv");
	unsigned int maxSize = 0;
	for (vector<string>::iterator f = files.begin(); f != files.end(); f++) {
		Mat_<uchar> t = imread(*f, CV_LOAD_IMAGE_GRAYSCALE);

				//imshow("Orig", t);

		Mat_<uchar> img(t.rows, t.cols);

		Sobel(t, img, t.depth(), 2, 2);

		Scalar m, sd;
		meanStdDev(t, m, sd);

		double mean = m.val[0];
		double stddev = sd.val[0];

		meanStdDev(img, m, sd);

		double meanSobel = m.val[0];
		double stddevSobel = sd.val[0];

		char objName[100];
		unsigned int iteration;

		sscanf((*f).c_str(), "%[^_]_%d.png", objName, &iteration);

		sds[objName][iteration] = stddevSobel;
		ms[objName][iteration] = meanSobel;
		if (sds[objName].size() > maxSize) {
			maxSize = sds[objName].size();
		}

		//		ofs << objName << "\t" << iteration << "\t" << mean << "\t" << stddev << "\t" << meanSobel << "\t" << stddevSobel << endl;

		//		equalizeHist(img, img2);


		//		imshow("Grad", img);

		//		waitKey(-1);
	}

	map<string, V>::iterator itObj;
	ofs << "Iteration";
	for (itObj = sds.begin(); itObj != sds.end(); itObj++) {
		ofs << "\t" << itObj->first << " (mean) \t" << itObj->first << " (sd)";
		maxSd[itObj->first] = max_element(sds[itObj->first].begin(),sds[itObj->first].end(), map_comparer)->second;
		minSd[itObj->first] = min_element(sds[itObj->first].begin(),
				sds[itObj->first].end(), map_comparer)->second;
		maxMean[itObj->first] = max_element(ms[itObj->first].begin(),
				ms[itObj->first].end(), map_comparer)->second;
		minMean[itObj->first] = min_element(ms[itObj->first].begin(),
				ms[itObj->first].end(), map_comparer)->second;

	}
	ofs << endl;

	for (unsigned int i = 1; i <= maxSize; i++) {
		ofs << i;
		for (itObj = sds.begin(); itObj != sds.end(); itObj++) {

			if (itObj->second.find(i) != itObj->second.end()) {
				ofs << "\t" << (ms[itObj->first][i] - minMean[itObj->first])
						/ (maxMean[itObj->first] - minMean[itObj->first]);
				ofs << "\t" << (sds[itObj->first][i] - minSd[itObj->first])
						/ (maxSd[itObj->first] - minSd[itObj->first]);
			} else {
				ofs << "\t\t";
			}
		}
		ofs << endl;
	}
}
/*!
 * Displays difference between two consecutive tomograms
 */
void testDiff() {
	Mat_<uchar> t;
	Mat_<uchar> t_prev;
	stringstream ss;
	t = imread("HeII_01.png", CV_LOAD_IMAGE_GRAYSCALE);
	t_prev = Mat_<uchar> (t.rows, t.cols);
	for (int i = 1; i <= 7; i++) {
		stringstream ss;
		ss << "HeII_0" << i << ".png";
		t = imread(ss.str(), CV_LOAD_IMAGE_GRAYSCALE);
		imshow("T", t);
		imshow("Prev", t_prev);
		imshow("Diff", t - t_prev);
		t_prev = t;

		waitKey(-1);
	}
}

int main() {

	testSobel();

	return 0;
}
